package com.kun.companion.core.ui.view;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.kun.companion.core.context.ContextService;
import com.kun.companion.core.exception.Assert;
import com.kun.companion.core.thread.AbstractThreadPool;
import com.kun.companion.core.thread.ComThreadPool;
import com.kun.companion.core.ui.KunComponent;
import com.kun.companion.core.ui.progress.KunProgressBar;
import com.kun.companion.core.util.ComUtil;
import javafx.concurrent.Worker;
import javafx.geometry.Pos;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import netscape.javascript.JSObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.concurrent.CompletableFuture;

/**
 * 高性能、低占用、高扩展的 WebView视图
 * 核心功能：
 * 1. 异步加载页面
 * 2. 异步执行 JavaScript
 * 3. 可控线程池管理
 * 4. 安全资源释放
 *
 * @author gzc
 * @since 2025/2/9
 */
public class KunWebViewPane extends BorderPane implements KunComponent {
    private static final Logger log = LoggerFactory.getLogger(KunWebViewPane.class);
    /**
     * 进度条高度占比，默认占整个BorderPane高度的1%，浏览器高度99%
     */
    public static final String PROGRESS_BAR_HEIGHT_RATIO = "0.01";
    /**
     * 浏览器视图
     */
    protected final WebView webView;
    /**
     * 浏览器引擎
     */
    protected final WebEngine webEngine;
    /**
     * 线程池用于异步任务管理
     */
    protected final AbstractThreadPool threadPool;
    /**
     * 进度条组件，用于显示页面加载进度
     */
    protected final ProgressBar progressBar;
    /**
     * JavaScript 的 window 对象，用于桥接 Java 和 JS
     */
    protected JSObject window;
    /**
     * 网页html结构
     */
    protected Document document;

    /**
     * 默认构造函数，使用默认线程池和进度条。
     */
    public KunWebViewPane() {
        this(ContextService.getBean(ComThreadPool.class));
    }

    /**
     * 构造函数，允许传入自定义进度条。
     *
     * @param progressBar 自定义进度条组件
     */
    public KunWebViewPane(ProgressBar progressBar) {
        this(ContextService.getBean(ComThreadPool.class), progressBar);
    }

    /**
     * 构造函数，允许传入自定义线程池。
     *
     * @param threadPool 自定义线程池
     */
    public KunWebViewPane(AbstractThreadPool threadPool) {
        this(threadPool, new KunProgressBar());
    }

    /**
     * 构造函数，允许传入自定义线程池和进度条。
     *
     * @param threadPool  自定义线程池
     * @param progressBar 自定义进度条组件
     */
    public KunWebViewPane(AbstractThreadPool threadPool, ProgressBar progressBar) {
        Assert.notNull(threadPool, "线程池为空");
        Assert.notNull(progressBar, "进度条组件为空");
        this.webView = new WebView();
        this.webEngine = webView.getEngine();
        this.threadPool = threadPool;
        this.progressBar = progressBar;
        // 初始化引擎配置、布局和预加载内容
        initializeEngine();
        onEngineReady();
        initializeLayout();
        setDocument(createDefaultHtmlDocument());
    }


    /**
     * 设置用户代理。
     *
     * @param userAgent 用户代理字符串
     */
    public void setUserAgent(String userAgent) {
        ComUtil.uiThreadRun(() -> webEngine.setUserAgent(userAgent));
    }

    public void setHtml(String htmlText) {
        setDocument(Jsoup.parse(htmlText));
    }

    public void setDocument(Document document) {
        this.document = document;
    }

    public Document getDocument() {
        return this.document;
    }

    /**
     * 异步加载页面（返回 Future 用于链式操作）。
     *
     * @param url 页面 URL
     * @return CompletableFuture<Void>
     */
    public CompletableFuture<Void> loadPageAsync(String url) {
        return threadPool.runAsync(() -> {
            log.debug("异步加载页面 -> {}", url);
            try {
                ComUtil.uiThreadRun(() -> webEngine.load(url));
            } catch (Exception e) {
                Assert.throwBizException(e, "加载页面失败 -> {} ", url);
            }
        });
    }

    /**
     * 异步执行 JavaScript 并通过 window 对象获取结果。
     *
     * @param jsCode JavaScript 代码
     * @return CompletableFuture<T>
     */
    public <T> CompletableFuture<T> executeJsWithWindowAsync(String jsCode) {
        return threadPool.supplyAsyncUI(() -> {
            Assert.notNull(window, "Window对象未初始化，页面尚未加载完成。");
            return (T) window.eval(jsCode);
        });
    }

    /**
     * 异步执行 JavaScript 并获取结果。
     *
     * @param jsCode JavaScript 代码
     * @return CompletableFuture<T>
     */
    public <T> CompletableFuture<T> executeJsAsync(String jsCode) {
        return threadPool.supplyAsyncUI(() -> {
            try {
                return (T) webEngine.executeScript(jsCode);
            } catch (Exception e) {
                Assert.throwBizException(e, "执行JS失败 -> {} ", jsCode);
            }
            return null;
        });
    }

    /**
     * 释放资源
     */
    @Override
    public void dispose() {
        // 释放FX资源
        ComUtil.uiThreadRun(() -> {
            webEngine.getLoadWorker().cancel();
            webEngine.load(null);
            webView.getEngine().load(null);
            webView.setDisable(true);
            KunComponent.dispose(progressBar);
        });
    }

    /**
     * 获取原始WebView实例（用于自定义扩展）
     */
    public WebView getWebView() {
        return webView;
    }

    /**
     * 预加载资源
     */
    public void preloadResources(String... resources) {
        if (ArrayUtil.isEmpty(resources)) {
            return;
        }
        StringBuilder content = new StringBuilder("<html><head>");
        for (String resource : resources) {
            content.append("<link rel='preload' href='").append(resource).append("' as='fetch'>");
        }
        content.append("</head></html>");
        ComUtil.uiThreadRun(() -> webEngine.loadContent(content.toString()));
    }

    /**
     * 预加载 HTML 内容。
     *
     * @param headText 头部内容
     * @param bodyText 主体内容
     * @param jsText   JavaScript 内容
     */
    public void preloadHtml(String headText, String bodyText, String jsText) {
        StringBuilder content = new StringBuilder("<html><head>");
        if (StrUtil.isNotBlank(headText)) {
            content.append(headText);
        }
        content.append("</head>");
        content.append("<body>");
        if (StrUtil.isNotBlank(bodyText)) {
            content.append(bodyText);
        }
        content.append("</body>");
        content.append("<script>");
        if (StrUtil.isNotBlank(jsText)) {
            content.append(jsText);
        }
        content.append("</script>");
        content.append("</html>");
        ComUtil.uiThreadRun(() -> webEngine.loadContent(content.toString()));
    }

    /**
     * 初始化布局，设置 WebView 和进度条的位置和大小。
     */
    protected void initializeLayout() {
        // 将进度条放置在顶部
        setTop(progressBar);
        // 将 WebView 放置在中心
        setCenter(webView);
        // 居中对齐进度条
        setAlignment(progressBar, Pos.CENTER);
        getStyleClass().setAll("kun-pane");
        setPrefSize(800, 500);
        // 动态调整进度条和 WebView 的宽度
        widthProperty().addListener((observable, oldValue, newValue) -> {
            this.progressBar.setPrefWidth(newValue.doubleValue());
            this.webView.setPrefWidth(newValue.doubleValue());
        });
        // 动态调整进度条和 WebView 的高度
        heightProperty().addListener((observable, oldValue, newValue) -> {
            BigDecimal multiply = BigDecimal.valueOf(newValue.doubleValue()).multiply(new BigDecimal(PROGRESS_BAR_HEIGHT_RATIO));
            this.progressBar.setPrefHeight(multiply.doubleValue());
            BigDecimal subtract = BigDecimal.valueOf(newValue.doubleValue()).subtract(multiply);
            this.webView.setPrefHeight(subtract.doubleValue());
        });
    }

    /**
     * 页面加载过程中触发的回调方法。
     *
     * @param oldValue 旧的加载进度值
     * @param newValue 新的加载进度值
     */
    protected void onPageLoading(Number oldValue, Number newValue) {
        // 默认为空
    }

    /**
     * 页面加载成功时的回调方法。
     * 子类可以重写此方法以实现自定义行为。
     */
    protected void onPageLoadSucceeded() {
        // 默认实现为空
    }

    /**
     * 页面加载失败时的回调方法。
     * 子类可以重写此方法以实现自定义行为。
     */
    protected void onPageLoadFailed() {
        // 默认实现为空
    }

    /**
     * 扩展点：引擎准备就绪时调用
     */
    protected void onEngineReady() {

    }

    /**
     * 扩展点：处理加载异常（可选重写）
     */
    protected void handleLoadError(Throwable throwable) {

    }

    /**
     * 初始化WebEngine基础配置
     */
    private void initializeEngine() {
        ComUtil.uiThreadRun(() -> {
            // 禁用上下文菜单以减少资源占用
            webView.setContextMenuEnabled(false);
            // 设置 WebView 的缓存策略
            webView.setCache(true);
            // 启用 JavaScript
            webEngine.setJavaScriptEnabled(true);
            // 设置用户代理（可选）
            webEngine.setUserAgent("KunCompanion/1.0");
            // 监听页面加载状态
            webView.getEngine().getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
                ComUtil.uiThreadRun(() -> {
                    if (newValue == Worker.State.SUCCEEDED) {
                        // 添加Java桥接方法暴露给JS
                        window = (JSObject) webEngine.executeScript("window");
                        window.setMember("Java", new JavaBridge());
                        // 更新进度条并触发加载完成回调
                        this.progressBar.setProgress(1D);
                        log.info("页面加载成功，网址 -> {}", webEngine.getLocation());
                        onPageLoadSucceeded();
                    } else if (newValue == Worker.State.FAILED) {
                        // 页面加载失败时，更新进度条并触发加载失败回调
                        this.progressBar.setProgress(1D);
                        log.error("页面加载失败，网址 -> {}", webEngine.getLocation());
                        onPageLoadFailed();
                        Worker<?> worker = webEngine.getLoadWorker();
                        Throwable exception = worker.getException();
                        if (exception != null) {
                            log.error("页面加载异常: {}", exception.getMessage(), exception);
                            handleLoadError(exception);
                        }
                    }

                });
            });
            // 监听文档加载完成事件
            webEngine.documentProperty().addListener((obs, oldDoc, newDoc) -> {
                if (newDoc != null) {
                    // 使用JS检测页面完全加载完成
                    webEngine.executeScript("window.addEventListener('load', function() { Java.onPageFullyLoaded(); })");
                }
            });
            // 监听网页加载进度变化
            webView.getEngine().getLoadWorker().progressProperty().addListener((observable, oldValue, newValue) -> {
                this.progressBar.setProgress(newValue.doubleValue());
                onPageLoading(oldValue, newValue);
            });
        });
    }

    private Document createDefaultHtmlDocument() {
        String defaultHtmlText = """
                <html>
                <head>
                    <meta charset="UTF-8">
                    <title></title>
                    <style></style>
                </head>
                <body></body>
                <script></script>
                </html>""";
        return Jsoup.parse(defaultHtmlText);
    }


    /**
     * Java 桥接类，用于暴露给 JavaScript。
     */
    private class JavaBridge {
        public void onPageFullyLoaded() {
            // 确保此时所有资源加载完成
            onPageLoadSucceeded();
        }
    }
}